﻿using System.Linq;
using System;
using System.Collections.Generic;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
using System.Collections;
using Org.BouncyCastle.Pkcs;
using System.IO;
using iTextSilverlight.text.pdf;
using iTextSilverlight.text.xml.xmp;

namespace FlexoWeb.Web.Data.Dokumente
{
    /// <summary>
    /// This class hold the certificate and extract private key needed for e-signature 
    /// </summary>
    class Cert
    {
        #region Attributes

        private string path = "";
        private Stream stream;
        private string password = "";
        private AsymmetricKeyParameter akp;
        private X509Certificate[] chain;

        #endregion

        #region Accessors
        public X509Certificate[] Chain
        {
            get { return chain; }
        }
        public AsymmetricKeyParameter Akp
        {
            get { return akp; }
        }

        public string Path
        {
            get { return path; }
        }

        public Stream Stream
        {
            get { return stream; }
        }

        public string Password
        {
            get { return password; }
            set { password = value; }
        }
        #endregion

        #region Helpers

        private void processCert()
        {
            string alias = null;
            Pkcs12Store pk12;

            //First we'll read the certificate file
            pk12 = new Pkcs12Store((Stream)stream, this.password.ToCharArray());//new FileStream(this.Path, FileMode.Open, FileAccess.Read), this.password.ToCharArray());

            //then Iterate throught certificate entries to find the private key entry
            IEnumerator i = pk12.Aliases.GetEnumerator();
            while (i.MoveNext())
            {
                alias = ((string)i.Current);
                if (pk12.IsKeyEntry(alias))
                    break;
            }

            this.akp = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            this.chain = new X509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
                chain[k] = ce[k].Certificate;

        }
        #endregion

        #region Constructors
        public Cert()
        { }
        public Cert(string cpath)
        {
            this.path = cpath;
            this.processCert();
        }
        public Cert(string cpath, string cpassword)
        {
            this.path = cpath;
            this.Password = cpassword;
            this.processCert();
        }

        public Cert(Stream stream, string cpassword)
        {
            this.stream = stream;
            this.Password = cpassword;
            this.processCert();
        }
        #endregion

    }

    /// <summary>
    /// This is a holder class for PDF metadata
    /// </summary>
    class MetaData
    {
        private Hashtable info;

        public Hashtable Info
        {
            get { return info; }
            set { info = value; }
        }

        public string Author
        {
            get { return (string)info["Author"]; }
            set { info.Add("Author", value); }
        }
        public string Title
        {
            get { return (string)info["Title"]; }
            set { info.Add("Title", value); }
        }
        public string Subject
        {
            get { return (string)info["Subject"]; }
            set { info.Add("Subject", value); }
        }
        public string Keywords
        {
            get { return (string)info["Keywords"]; }
            set { info.Add("Keywords", value); }
        }
        public string Producer
        {
            get { return (string)info["Producer"]; }
            set { info.Add("Producer", value); }
        }

        public string Creator
        {
            get { return (string)info["Creator"]; }
            set { info.Add("Creator", value); }
        }

        public Hashtable getMetaData()
        {
            return this.info;
        }
        public byte[] getStreamedMetaData()
        {
            MemoryStream os = new System.IO.MemoryStream();
            XmpWriter xmp = new XmpWriter(os, this.info);
            xmp.Close();
            return os.ToArray();
        }

    }


    /// <summary>
    /// this is the most important class
    /// it uses iTextSharp library to sign a PDF document
    /// </summary>
    class PDFSigner
    {
        string inputPDF = "";
        string outputPDF = "";
        Cert myCert;
        MetaData metadata;

        public PDFSigner()
        {

        }

        public PDFSigner(string input, string output)
        {
            inputPDF = input;
            outputPDF = output;
        }

        public PDFSigner(string input, string output, Cert cert)
        {
            inputPDF = input;
            outputPDF = output;
            myCert = cert;
        }
        public PDFSigner(string input, string output, MetaData md)
        {
            inputPDF = input;
            outputPDF = output;
            metadata = md;
        }
        public PDFSigner(string input, string output, Cert cert, MetaData md)
        {
            inputPDF = input;
            outputPDF = output;
            myCert = cert;
            metadata = md;
        }

        public void Verify()
        {
        }


        public byte[] Sign(Stream pdfStream, Stream zertifikatStream)
        {
            PdfReader reader = new PdfReader(pdfStream);
            MemoryStream outputStream = new MemoryStream();

            PdfStamper st = PdfStamper.CreateSignature(reader, outputStream, '\0', null, true);
            myCert = new Cert(zertifikatStream, "sksc2011");
            //st.MoreInfo = metadata.getMetaData();
            //st.XmpMetadata = metadata.getStreamedMetaData();
            PdfSignatureAppearance sap = st.SignatureAppearance;

            sap.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED;
            sap.SetCrypto(myCert.Akp, myCert.Chain, null, PdfName.ADOBE_PPKMS);// PdfSignatureAppearance.VERISIGN_SIGNED);// PdfName.ADBE_PKCS7_SHA1); //PdfSignatureAppearance.WINCER_SIGNED);
            //   sap.Reason = SigReason;

            // sap.Contact = SigContact;
            //sap.Location = SigLocation;
            //sap.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED;

            // iTextSharp.text.Image image = sap.GetImage();

            //if (visible)
            //sap.SetVisibleSignature(new iTextSharp.text.Rectangle(50, 50, 250, 100), 1, "Signature");

            st.Close();
            return outputStream.GetBuffer();
        }

    }
}


